home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xgrabsc / convert.hc < prev    next >
Encoding:
Text File  |  1995-05-09  |  9.2 KB  |  334 lines

  1. /*========================================================================
  2.  *
  3.  * Name - convert.hc
  4.  *
  5.  * ccs version:    1.6
  6.  *
  7.  * ccsid:    @(#)convert.hc    1.6 - 04/22/93 16:27:04
  8.  * from:     ccs/s.convert.hc
  9.  * date:     06/28/93 09:14:48
  10.  *
  11.  * Description:  color->black&white conversions for xgrabsc
  12.  *
  13.  *               see cpyright.h for copyright information
  14.  *
  15.  *
  16.  *========================================================================
  17.  */
  18.  
  19.  
  20. /*
  21.  * convert a pixmap image into a bitmap image
  22.  */
  23. pixmap2bitmap(image)
  24.   imageInfo *image;
  25. {
  26.   XImage *ximage = image->ximage;
  27.   int x, y;
  28.   word v, black, mid;
  29.   dw total, blackrgb, midrgb, lowDelta, l;
  30.   XImage *newImage;
  31.   byte *newBytes;
  32.   int usedCount;
  33.   int blackp, whitep;
  34.  
  35.   if (ximage->bits_per_pixel == 1  ||  image->numcells < 1)
  36.     return;
  37.  
  38.  
  39.   blackp = BlackPixel(hDisplay,hScreen);
  40.   whitep = WhitePixel(hDisplay,hScreen);
  41.  
  42.   /* get the darkest color */
  43.   blackrgb = 0x2FFFD;  /* 3 * 0xFFFF == white */
  44.   usedCount = total = 0;
  45.   for (x=0; x<image->numcells; x++) {
  46.     if (image->used[x]) {
  47.       l = (unsigned)image->red[x]
  48.           +(unsigned)image->green[x]
  49.           +(unsigned)image->blue[x];
  50.       if (l <= blackrgb) {
  51.         black = x;
  52.         blackrgb = l;
  53.       }
  54.       total += l;
  55.       usedCount++;
  56.     }
  57.   }
  58.   /* now find the mid color and use it as the cut-off for black */
  59.   midrgb = total / usedCount;
  60.   lowDelta = 0x2FFFD;
  61.   for (x=0; x<image->numcells; x++) {
  62.     if (image->used[x]) {
  63.       l = (unsigned)image->red[x]
  64.           +(unsigned)image->green[x]
  65.           +(unsigned)image->blue[x];
  66.       l -= midrgb;
  67.       if (l < lowDelta) {
  68.         mid = x;
  69.         lowDelta = l;
  70.       }
  71.     }
  72.   }
  73.   midrgb = (unsigned)image->red[mid]
  74.            +(unsigned)image->green[mid]
  75.            +(unsigned)image->blue[mid];
  76.  
  77.   /* create a bitmap image */
  78.   x = (ximage->width + 7) / 8;
  79.   newBytes = (byte *)malloc(x * ximage->height);
  80.   memset(newBytes, 0, x * ximage->height);
  81.   newImage = XCreateImage(hDisplay, DefaultVisual(hDisplay, hScreen),
  82.                 1, XYBitmap, 0, newBytes, ximage->width, ximage->height,
  83.                 8, x);
  84.   if (!newImage) {
  85.     fprintf(stderr, "%s: unable to create bitmap for conversion\n",
  86.       programName);
  87.     XCloseDisplay(hDisplay);
  88.     exit(3);
  89.   }
  90.   /* pound the pixels into it */
  91.   for (y = 0; y < ximage->height; y++) {
  92.     for (x = 0; x < ximage->width; x++) {
  93.       v = XGetPixel(ximage, x, y);
  94.       l = (dw)image->red[v]+(dw)image->green[v]+(dw)image->blue[v];
  95.       XPutPixel(newImage, x, y, l<midrgb? blackp : whitep);
  96.     }
  97.   }
  98.   free(ximage->data);
  99.   memcpy((char *)ximage, (char *)newImage, sizeof(XImage));
  100.   free(newImage);
  101.  
  102.   memset((char *)image->used, 0, MAX_CELLS);
  103.   image->used[whitep] = 1;
  104.   image->used[blackp] = 1;
  105.   image->numcells = 2;
  106. }
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114. #define GRAYS    17 /* ((4 * 4) + 1) patterns for a good dither */
  115. #define GRAYSTEP ((dw)(65536 / GRAYS))
  116.  
  117. static byte DitherBits[GRAYS][4] = {
  118.   0xf, 0xf, 0xf, 0xf,
  119.   0xe, 0xf, 0xf, 0xf,
  120.   0xe, 0xf, 0xb, 0xf,
  121.   0xa, 0xf, 0xb, 0xf,
  122.   0xa, 0xf, 0xa, 0xf,
  123.   0xa, 0xd, 0xa, 0xf,
  124.   0xa, 0xd, 0xa, 0x7,
  125.   0xa, 0x5, 0xa, 0x7,
  126.   0xa, 0x5, 0xa, 0x5,
  127.   0x8, 0x5, 0xa, 0x5,
  128.   0x8, 0x5, 0x2, 0x5,
  129.   0x0, 0x5, 0x2, 0x5,
  130.   0x0, 0x5, 0x0, 0x5,
  131.   0x0, 0x4, 0x0, 0x5,
  132.   0x0, 0x4, 0x0, 0x1,
  133.   0x0, 0x0, 0x0, 0x1,
  134.   0x0, 0x0, 0x0, 0x0
  135.   };
  136.  
  137. /* halftone or dither a color image, changing it into a monochrome
  138.  * image
  139.  */
  140. pixmap2halftone(image, dither)
  141.   imageInfo *image;
  142.   ditherType dither;    /* type of dithering to perform */
  143. {
  144.   XImage *ximage = image->ximage;
  145.   XImage *newImage;
  146.   byte   *newBytes, *ditherBits;
  147.   word   dindex;  /* index into dither array */
  148.   dw     color;   /* pixel color */
  149.   word  *index;   /* index into dither array for a given pixel */
  150.   word   x, y;    /* random counters */
  151.   word   x4, y4;
  152.   register word   w, h;
  153.   register byte  bits;
  154.   char  *str;
  155.   dw    intensity;
  156.   int   maxIntensity, threshold;
  157.   word  *fsIndex;
  158.   int   err, i, ximageW, ximageH, rowL;
  159.   int   *row1, *row2;
  160.   int blackp = BlackPixel(hDisplay,hScreen);
  161.   int whitep = WhitePixel(hDisplay,hScreen);
  162.  
  163.   if (ximage->depth <= 1  ||  dither == NO_DITHER)
  164.     return;
  165.  
  166.   ximageW = ximage->width;
  167.   rowL    = ximageW - 1;
  168.   ximageH = ximage->height;
  169.  
  170.   if (verbose) {
  171.     switch (dither) {
  172.       case MATRIX_HALFTONE:
  173.         str = "Matrix halfton";
  174.         break;
  175.       case MATRIX_DITHER:
  176.         str = "Matrix dither";
  177.         break;
  178.       case FS_DITHER:
  179.         str = "Floyd-Steinberg dither";
  180.         break;
  181.       default:
  182.         fprintf(stderr, "%s: unknown type of dithering requested.  Exiting...\n",
  183.             programName);
  184.         exit(3);
  185.     }
  186.     fprintf(stderr, "%s: %sing image...", programName, str);
  187.     fflush(stderr);
  188.   }
  189.  
  190.   /* create a bitmap image */
  191.   x = (dither == MATRIX_HALFTONE)? 4 : 1;
  192.   w = ((ximageW + 7) / 8) * x;
  193.   h = ximageH * x;
  194.   newBytes = (byte *)malloc(w * h);
  195.   memset((char *)newBytes, whitep=1?255:0, w * h);
  196.   newImage = XCreateImage(hDisplay, DefaultVisual(hDisplay, hScreen),
  197.                 1, XYBitmap, 0, newBytes,
  198.                 ximageW * x,
  199.                 h,
  200.                 8, w);
  201.   if (!newImage) {
  202.     fprintf(stderr, "%s: unable to create bitmap for conversion\n",
  203.       programName);
  204.     XCloseDisplay(hDisplay);
  205.     exit(3);
  206.   }
  207.  
  208.   /* if the number of possible pixels isn't very large, build an array
  209.    * which we index by the pixel value to find the dither array index
  210.    * by color brightness.  we do this in advance so we don't have to do
  211.    * it for each pixel.  things will break if a pixel value is greater
  212.    * than (1 << depth), which is bogus anyway.  this calculation is done
  213.    * on a per-pixel basis if the colormap is too big.
  214.    */
  215.  
  216.   if (ximage->depth <= 16) {
  217.     index= (word *)malloc(sizeof(word) * MAX_CELLS);
  218.     fsIndex= (word *)malloc(sizeof(word) * MAX_CELLS);
  219.     if (index)
  220.       for (x= 0; x < image->numcells; x++) {
  221.         fsIndex[x] = (word)(0.30 * image->red[x] +
  222.                           0.59 * image->green[x] +
  223.                           0.11 * image->blue[x]);
  224.         index[x] = fsIndex[x]/GRAYSTEP;
  225.         if (index[x] >= GRAYS)
  226.           index[x] = GRAYS - 1;
  227.       }
  228.   }
  229.   else
  230.     index = fsIndex = NULL;
  231.  
  232.   if (dither == FS_DITHER) {
  233.     maxIntensity = 65535;
  234.     threshold = maxIntensity/2;
  235.     row1 = (int *)malloc(ximageW*sizeof(int));
  236.     row2 = (int *)malloc(ximageW*sizeof(int));
  237.     /* initialize row2 */
  238.     for (x= 0; x < ximageW; x++) {
  239.       color = XGetPixel(ximage, x, 0);
  240.       row2[x] = fsIndex? fsIndex[color] :
  241.                   (dw)(0.30*image->red[color] +
  242.                    0.59*image->green[color] +
  243.                    0.11*image->blue[color]);
  244.     }
  245.     for (y= 0; y < ximageH; y++) {
  246.       /* row1 := row2 */
  247.       memcpy((char *)row1, (char *)row2, ximageW*sizeof(int));
  248.       /* Fill in next row */
  249.       if (y != ximageH-1)
  250.         for (x= 0; x < ximageW; x++) {
  251.           color = XGetPixel(ximage, x, y+1);
  252.           row2[x] = fsIndex? fsIndex[color] :
  253.                       (dw)(0.30*image->red[color] +
  254.                        0.59*image->green[color] +
  255.                        0.11*image->blue[color]);
  256.         }
  257.       for (x= 0; x < ximageW; x++) {
  258.         color = XGetPixel(ximage, x, y);
  259.         if ((i = row1[x]) > threshold)
  260.           err = i - maxIntensity;
  261.         else {
  262.           XPutPixel(newImage, x, y, blackp);
  263.           err = i;
  264.         }
  265.         /* Diagonal gets 1/4 of error. */
  266.         if (x < rowL)
  267.       row2[x+1] += err/4;
  268.  
  269.         /* Right and below get 3/8 of error */
  270.         err = err*3/8;
  271.         row2[x] += err;
  272.         if (x < rowL)
  273.       row1[x+1] += err;
  274.       }
  275.     }
  276.     if (row1)  free(row1);
  277.     if (row2)  free(row2);
  278.   }
  279.  
  280.  
  281.   else {  /* matrix dither or halftone */
  282.  
  283.     for (y= 0; y < ximageH; y++) {
  284.       for (x= 0; x < ximageW; x++) {
  285.         color = XGetPixel(ximage, x, y);
  286.         dindex = index? index[color] :
  287.                     (dw)(0.30*image->red[color] +
  288.                      0.59*image->green[color] +
  289.                      0.11*image->blue[color])/GRAYSTEP;
  290.         if (dindex >= GRAYS)  /* catch rounding errors */
  291.           dindex= GRAYS - 1;
  292.         if (dither == MATRIX_DITHER) {
  293.           if (DitherBits[dindex][y & 3] & (1 << (x & 3)))
  294.              XPutPixel(newImage, x, y, blackp);
  295.         }
  296.         else { /* halftone */
  297.           /* loop for the four Y bits in the dither pattern, putting all
  298.            * four X bits in at once.  if you think this would be hard to
  299.            * change to be an NxN dithering array, you're right, since we're
  300.            * banking on the fact that we need only shift the mask based on
  301.            * whether x is odd or not.  an 8x8 array wouldn't even need that,
  302.            * but blowing an image up by 64x is probably not a feature.
  303.            */
  304.           ditherBits = &(DitherBits[dindex][0]);
  305.           x4 = x * 4;
  306.           y4 = y * 4;
  307.           for (h= 0; h < 4; h++) {
  308.             bits = ditherBits[h];
  309.             for (w=0; w < 4; w++) {
  310.               XPutPixel(newImage, x4+w, y4+h, bits & 1 ? blackp : whitep);
  311.               bits /= 2;
  312.             }
  313.           }
  314.         }
  315.       }
  316.     }
  317.   }
  318.  
  319.   if (verbose)
  320.     fputc('\n', stderr);
  321.  
  322.   free(ximage->data);
  323.   memcpy((char *)ximage, (char *)newImage, sizeof(XImage));
  324.   free(newImage);
  325.   if (index) free(index);
  326.   if (fsIndex) free(fsIndex);
  327.  
  328.   memset((char *)image->used, 0, MAX_CELLS);
  329.   image->used[whitep] = 1;
  330.   image->used[blackp] = 1;
  331.   image->numcells = 2;
  332. }
  333.  
  334.